#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <execinfo.h>

#include <bits/types/stack_t.h>


//cc -rdynamic prog.c -o prog
#define BT_BUF_SIZE 10
void showBacktrace(void)
{
    int j, nptrs;
    void *buffer[BT_BUF_SIZE];
    char **strings;

    nptrs = backtrace(buffer, BT_BUF_SIZE);
    printf("backtrace() returned %d addresses\n", nptrs);

    /* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO)
              would produce similar output to the following: */

    strings = backtrace_symbols(buffer, nptrs);
    if (strings == NULL)
    {
        perror("backtrace_symbols");
        exit(EXIT_FAILURE);
    }

    for (j = 0; j < nptrs; j++)
        printf("%s\n", strings[j]);
    free(strings);
}

/** 信号处理函数 */
void sig_handler(int sig)
{
    switch (sig)
    {
    case SIGSEGV:
        showBacktrace();
        break;
    default:
        ;
        break;
    }
    exit(-1);
}
/** 信号处理函数 */
sighandler_t ruby_signal(int signum, sighandler_t handler)
{
    static struct sigaction sigact, old;
    if (signum == SIGSEGV)
        sigact.sa_flags |= SA_ONSTACK;

    sigact.sa_handler = handler; /* Address of a signal handler */
    if (sigaction(signum, &sigact, &old) < 0)
        perror("in ruby_signal() sigaction()");

    return old.sa_handler;
}
/** 栈溢出测试 */
unsigned stackOver(unsigned x){return stackOver(x) + 1;}
/** 备用栈注册 */
void register_sigaltstack()
{
    static int is_altstack_defined = 0;
    stack_t newSS, oldSS;
    if (is_altstack_defined)
        return;

    newSS.ss_sp = malloc(SIGSTKSZ);
    if (!newSS.ss_sp)
    {
        perror("in register_sigaltstack() malloc():");
        return;
    }
    newSS.ss_size = SIGSTKSZ;
    newSS.ss_flags = 0;
    if (sigaltstack(&newSS, &oldSS) == -1)
    {
        perror("in register_sigaltstack()  sigaltstack():");
        return;
    }
    is_altstack_defined = 1;
}
int main(int argc,char *argv[])
{
    register_sigaltstack();
    ruby_signal(SIGSEGV, sig_handler);
    stackOver(0);
    return 0;
}